//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V0.1.4
#include "1bus_driver.h"
#include <stdio.h>

/*DS18B20命令枚举*/
typedef enum
{
	DS18B20_Read_64Bit_ROM_Code     = 0x33,//获取8字节64位ROM编码,用于单个设备
	DS18B20_Matching_64Bit_ROM_Code = 0x55,//匹配8字节64位ROM编码
	DS18B20_Search_64Bit_ROM_Code   = 0xf0,//搜索8字节64位ROM编码
	DS18B20_Skip_64Bit_ROM_Code     = 0xcc,//跳过8字节64位ROM编码
	DS18B20_Alert_Search            = 0xec,//警报搜索，超温的传感器才响应

	DS18B20_Start_Temp_Convert      = 0x44,//温度转换指令
	DS18B20_Read_RAM_Value          = 0xbe,//读取暂存寄存器,共9字节
	DS18B20_Set_Alert_Temp_Accuracy = 0x4e,//配置高温报警低温报警及温度精度
	DS18B20_RAM_Value_Copy_EEPROM   = 0x48,//将配置好的寄存器值拷贝到EEPROM里
	DS18B20_EEPROM_Value_Copy_RAM   = 0xb8,//将EEPROM里的数据拷贝到寄存器里
	DS18B20_Read_Power_Mode         = 0xb4,//寄生供电得到0，外接供电得到1
}WHT_DS18B20_Cmd_enum;

/*DS18B20实时数据结构体*/
typedef struct
{
	struct
	{
		char Temp_Low;                    //转换温度的低8位
		char Temp_Hig;                    //转换温度的高8位
		char Alert_Temp_Hig;              //报警高温
		char Alert_Temp_Low;              //报警低温
		unsigned char Accuracy;           //温度精度，WHT_DS18B20_Accuracy_Sel_enum
		unsigned char Reserve0;           //保留默认值0xff
		unsigned char Reserve1;           //保留
		unsigned char Reserve2;           //保留默认值0x10
		unsigned char CRC8;               //CRC8校验码 CRC = X8 + X5 + X4 + 1
	}RAM;
	struct
	{
		unsigned char Type;                //系列编码0x28(DS18B20)
		unsigned char Serial_Number[6];    //48位序列号
		unsigned char CRC8;                //CRC8
	}ROM;                                  //我的ID是0x070822816d3d9928,打印ID示例_1BUS_LOGI("DS18B20 ID = 0x%llx\r\n", *((unsigned long long*)&DS18B20.WHT_DS18B20_Reg_Value->ROM));
	WHT_DS18B20_Power_Mode_enum Power_Mode;//供电模式
	float TEMP;                            //当前温度
}WHT_DS18B20_Reg_t;


/********************************1BUS read & write********************************/
static void WHT_1BUS_Write_1Bit(WHT_DS18B20_Config_t* config, WHT_GPIO_State_enum status)
{
	*config->BUS_Set_State = Low;
	WHT_Delay_us(2);             //延迟大于1us
	*config->BUS_Set_State = status;
	WHT_Delay_us(60);            //延迟60us让DS18B20好采样
	*config->BUS_Set_State = Hig;//释放总线
	WHT_Delay_us(2);             //延迟大于1us
}
static WHT_GPIO_State_enum WHT_1BUS_Read_1Bit(WHT_DS18B20_Config_t* config)
{
	WHT_GPIO_State_enum status;

	*config->BUS_Set_State = Low;
	WHT_Delay_us(2);
	*config->BUS_Set_State = Hig;//释放总线
	WHT_Delay_us(10);            //延迟个10us时间在采集数据
	status = (WHT_GPIO_State_enum)*config->BUS_Get_State;
	*config->BUS_Set_State = Hig;//释放总线
	WHT_Delay_us(45);            //延迟45us
	return status;
}

static void WHT_1BUS_Write_1Byte(WHT_DS18B20_Config_t* config, unsigned char datax)
{
	for (unsigned char i = 0x01; i != 0x00; i<<= 1)//LSB
	{
		if ((datax & i) != 0x00)
			WHT_1BUS_Write_1Bit(config, Hig);
		else
			WHT_1BUS_Write_1Bit(config, Low);
	}
}
static unsigned char WHT_1BUS_Read_1Byte(WHT_DS18B20_Config_t* config)
{
	unsigned char datax = 0;

	for (unsigned char i = 0x01; i != 0x00; i <<= 1)//LSB
	{
		if (WHT_1BUS_Read_1Bit(config) == Hig)
			datax |= i;
	}
	return datax;
}
/********************************1BUS read & write********************************/


/*GPIO初始化*/
static void GPIO_Init_Config(WHT_DS18B20_Config_t* config)
{
	WHT_GPIO_BSP.WHT_Set_Clock(config->BUS_GPIO_Port, ENABLE);
	WHT_GPIO_BSP.WHT_Register_Bit_Output(config->BUS_GPIO_Port, config->BUS_GPIO_Pin, &config->BUS_Set_State);
	WHT_GPIO_BSP.WHT_Register_Bit_Input(config->BUS_GPIO_Port, config->BUS_GPIO_Pin, &config->BUS_Get_State);
	WHT_GPIO_BSP.WHT_Set_Pin(config->BUS_GPIO_Port, config->BUS_GPIO_Pin, Hig);
	WHT_GPIO_BSP.WHT_Set_Mode(config->BUS_GPIO_Port, config->BUS_GPIO_Pin, Mode_Out_OD);//开漏模式，必须要有上拉电阻
}


/*复位初始化DS18B20*/
static ErrorStatus WHT_DS18B20_Driver_Reset(WHT_DS18B20_Config_t* config)
{
	unsigned char Overtime = 0;

	*config->BUS_Set_State = Low;//拉低总线
	WHT_Delay_us(480);
	*config->BUS_Set_State = Hig;//释放总线

	do
	{
		WHT_Delay_us(1);
		if (Overtime++ >= 60)
		{
			_1BUS_LOGI("WHT_DS18B20_Driver_Reset ERROR\r\n");
			return ERROR;        //器件不存在或硬件损坏
		}
	} while (*config->BUS_Get_State != Low);//等待应答信号
	Overtime = 0;

	do
	{
		WHT_Delay_us(1);
		if (Overtime++ >= 240)
			return ERROR;        //通讯异常
	} while (*config->BUS_Get_State == Low);//等待器件释放总线

	return SUCCESS;
}

/*匹配ROM*/
static void WHT_DS18B20_Driver_Matching_ROM(WHT_DS18B20_Config_t* config, WHT_DS18B20_Cache_t* cache, FlagStatus matching_rom)
{
	if (matching_rom == SET)
	{
		WHT_1BUS_Write_1Byte(config, DS18B20_Matching_64Bit_ROM_Code);//匹配ROM编码
		for (unsigned char i = 0; i < 8; i++)
		{
			WHT_1BUS_Write_1Byte(config, cache->ROM_Code[i]);
		}
	}
	else
	{
		WHT_1BUS_Write_1Byte(config, DS18B20_Skip_64Bit_ROM_Code);//跳过8字节64位ROM编码
	}
}

/*读取DS18B20 ROM编码*/
static void WHT_DS18B20_Driver_Get_Rom_Code(WHT_DS18B20_Config_t* config, WHT_DS18B20_Cache_t* cache)
{
	if (WHT_DS18B20_Driver_Reset(config) == ERROR)
		return;
	
	WHT_1BUS_Write_1Byte(config, DS18B20_Read_64Bit_ROM_Code);
	for (unsigned char i = 0; i < 8; i++)
	{
		((unsigned char*)cache->ROM_Code)[i] = WHT_1BUS_Read_1Byte(config);
	}
}

/*配置高温报警温度和低温报警温度和温度精度*/
static void WHT_DS18B20_Driver_Set_Alarm_Temp_Accuracy(WHT_DS18B20_Config_t* config, WHT_DS18B20_Cache_t* cache, FlagStatus matching_rom)
{
	if (WHT_DS18B20_Driver_Reset(config) == ERROR)
		return;
	
	WHT_DS18B20_Driver_Matching_ROM(config, cache, matching_rom);
	WHT_1BUS_Write_1Byte(config, DS18B20_Set_Alert_Temp_Accuracy);//配置寄存器指令
	WHT_1BUS_Write_1Byte(config, cache->Alert_Temp_Hig);          //配置高温报警温度 最高位为1则表示负温度，为0则表示正温度，±1℃
	WHT_1BUS_Write_1Byte(config, cache->Alert_Temp_Low);          //配置低温报警温度
	WHT_1BUS_Write_1Byte(config, cache->Accuracy);                //温度精度
}

/*拷贝配置好的寄存器的值到EEPROM里*/
static void WHT_DS18B20_Driver_RAM_Value_Copy_EEPROM(WHT_DS18B20_Config_t* config, WHT_DS18B20_Cache_t* cache, FlagStatus matching_rom)
{
	if (WHT_DS18B20_Driver_Reset(config) == ERROR)
		return;
	
	WHT_DS18B20_Driver_Matching_ROM(config, cache, matching_rom);
	WHT_1BUS_Write_1Byte(config, DS18B20_RAM_Value_Copy_EEPROM);//将配置好的寄存器的值拷贝到EEPROM里
	#ifdef _1BUS_RTOS_Task_Delay
		vTaskDelay(10 / portTICK_RATE_MS);
	#else
		WHT_Delay_ms(10);
	#endif // _1BUS_RTOS_Task_Delay
}

/*召回EEPROM里的3个字节数据到寄存器对应里面（高温、低温、精度）*/
static void WHT_DS18B20_Driver_EEPROM_Value_Copy_RAM(WHT_DS18B20_Config_t* config, WHT_DS18B20_Cache_t* cache, FlagStatus matching_rom)
{
	if (WHT_DS18B20_Driver_Reset(config) == ERROR)
		return;
	
	WHT_DS18B20_Driver_Matching_ROM(config, cache, matching_rom);
	WHT_1BUS_Write_1Byte(config, DS18B20_EEPROM_Value_Copy_RAM);//操作指令将EEPROM里的数据拷贝到寄存器里

	if (WHT_DS18B20_Driver_Reset(config) == ERROR)
		return;
	
	WHT_DS18B20_Driver_Matching_ROM(config, cache, matching_rom);
	WHT_1BUS_Write_1Byte(config, DS18B20_Read_RAM_Value);       //读取暂存寄存器

	for (unsigned char i = 0; i < 9; i++)
	{
		((unsigned char*)cache)[i] = WHT_1BUS_Read_1Byte(config);
	}
}

/*获取供电模式*/
static void WHT_DS18B20_Driver_Get_Power_Mode(WHT_DS18B20_Config_t* config, WHT_DS18B20_Cache_t* cache, FlagStatus matching_rom)
{
	if (WHT_DS18B20_Driver_Reset(config) == ERROR)
		return;
	
	WHT_DS18B20_Driver_Matching_ROM(config, cache, matching_rom);
	WHT_1BUS_Write_1Byte(config, DS18B20_Read_Power_Mode);       //获取供电模式

	((WHT_DS18B20_Reg_t*)cache)->Power_Mode = WHT_1BUS_Read_1Bit(config) == Low ? BUS_Power_Mode : DC_Power_Mode;
}

/*转换温度*/
static ErrorStatus WHT_DS18B20_Driver_Convert_Temp(WHT_DS18B20_Config_t* config, WHT_DS18B20_Cache_t* cache, FlagStatus matching_rom)
{
	unsigned short Delay_Time = Accuracy_12Bit_Delay_ms;

	if (WHT_DS18B20_Driver_Reset(config) == ERROR)
		return ERROR;
	
	switch (cache->Accuracy)
	{
	case Accuracy_9Bit :Delay_Time = Accuracy_9Bit_Delay_ms;  break;
	case Accuracy_10Bit:Delay_Time = Accuracy_10Bit_Delay_ms; break;
	case Accuracy_11Bit:Delay_Time = Accuracy_11Bit_Delay_ms; break;
	case Accuracy_12Bit:Delay_Time = Accuracy_12Bit_Delay_ms; break;
	default:
		return ERROR;
	}

	WHT_DS18B20_Driver_Matching_ROM(config, cache, matching_rom);
	WHT_1BUS_Write_1Byte(config, DS18B20_Start_Temp_Convert);   //温度转换指令
	#ifdef _1BUS_RTOS_Task_Delay
		vTaskDelay(Delay_Time / portTICK_RATE_MS + 1);
	#else
		WHT_Delay_ms(Delay_Time);
	#endif // _1BUS_RTOS_Task_Delay
	return SUCCESS;
}

/*读取DS18B20的温度*/
static ErrorStatus WHT_DS18B20_Driver_Get_Temp(WHT_DS18B20_Config_t* config, WHT_DS18B20_Cache_t* cache, FlagStatus matching_rom)
{//特殊备注：注意类型在运算的时候如果结果大于此变量类型则应该强制转换大的类型
	short TEMP;
	WHT_DS18B20_Reg_t* DS18B20 = (WHT_DS18B20_Reg_t*)cache;

	if (WHT_DS18B20_Driver_Reset(config) == ERROR)
		return ERROR;
	
	WHT_DS18B20_Driver_Matching_ROM(config, cache, matching_rom);
	WHT_1BUS_Write_1Byte(config, DS18B20_Read_RAM_Value); //读取暂存寄存器

	DS18B20->RAM.Temp_Low = WHT_1BUS_Read_1Byte(config);  //温度的低8位
	DS18B20->RAM.Temp_Hig = WHT_1BUS_Read_1Byte(config);  //温度的高8位
	WHT_DS18B20_Driver_Reset(config);                     //强制复位，后面的数据不要了
	TEMP = (DS18B20->RAM.Temp_Hig << 8) | DS18B20->RAM.Temp_Low;
	_1BUS_LOGI("DS18B20 TEMP = 0x%x\r\n", TEMP);

	switch (DS18B20->RAM.Accuracy)
	{
	case Accuracy_9Bit:
		TEMP >>= 3;
		DS18B20->TEMP = (float)TEMP * 0.5f;
		break;
	case Accuracy_10Bit:
		TEMP >>= 2;
		DS18B20->TEMP = (float)TEMP * 0.25f;
		break;
	case Accuracy_11Bit:
		TEMP >>= 1;
		DS18B20->TEMP = (float)TEMP * 0.125f;
		break;
	case Accuracy_12Bit:
		TEMP >>= 0;
		DS18B20->TEMP = (float)TEMP * 0.0625f;
		break;
	default:
		return ERROR;
	}
	return SUCCESS;
}

/*搜索温度报警状态*/
static FlagStatus WHT_DS18B20_Driver_Get_Temp_Alert_Status(WHT_DS18B20_Config_t* config, WHT_DS18B20_Cache_t* cache, FlagStatus matching_rom)
{
	if (WHT_DS18B20_Driver_Reset(config) == ERROR)
		return RESET;
	
	// 发送报警搜索命令
	WHT_1BUS_Write_1Byte(config, DS18B20_Alert_Search);

	if (matching_rom == RESET)
	{
        // 搜索任意报警设备
        // 读取一位和它的补码
		unsigned char id_bit = WHT_1BUS_Read_1Bit(config);
		unsigned char cmp_id_bit = WHT_1BUS_Read_1Bit(config);

        // 如果两个位都为1，表示没有报警设备 否则有设备响应报警搜索
		return (id_bit && cmp_id_bit) ? RESET : SET;
	}
	else
	{
		unsigned char id_bit_number;
		unsigned char last_zero, rom_byte_number;
		unsigned char id_bit, cmp_id_bit;
		unsigned char rom_byte_mask, search_direction;
		
		// 初始化搜索变量
		id_bit_number = 1;
		last_zero = 0;
		rom_byte_number = 0;
		rom_byte_mask = 1;

        // 搜索特定ROM设备的报警状态
        // 我们需要检查特定设备是否报警
        
        // 循环处理64位ROM代码
        do {
            // 读取一位和它的补码
            id_bit = WHT_1BUS_Read_1Bit(config);
            cmp_id_bit = WHT_1BUS_Read_1Bit(config);
            
            if (id_bit && cmp_id_bit)
            {
                // 两个位都为1表示没有设备响应
                return RESET;
            }
            else
            {
                if (id_bit != cmp_id_bit)
                {
                    // 位不同，表示没有冲突
                    // 检查是否与目标ROM的位匹配
                    unsigned char target_bit = (cache->ROM_Code[rom_byte_number] & rom_byte_mask) ? 1 : 0;
                    if (id_bit != target_bit)
                    {
                        // 不匹配，设备不存在或没有报警
                        return RESET;
                    }
                    
                    search_direction = id_bit;
                }
                else
                {
                    // 位相同，表示有冲突
                    // 使用目标ROM的位来决定方向
                    search_direction = (cache->ROM_Code[rom_byte_number] & rom_byte_mask) ? 1 : 0;
                    
                    if (search_direction == 0)
                    {
                        last_zero = id_bit_number;
                    }
                }
                
                // 写入选择的方向
                WHT_1BUS_Write_1Bit(config, search_direction);
                
                // 移动到下一位
                id_bit_number++;
                rom_byte_mask <<= 1;
                
                // 移动到下一个字节
                if (rom_byte_mask == 0)
                {
                    rom_byte_number++;
                    rom_byte_mask = 1;
                }
            }
        } while (rom_byte_number < 8);
        
        // 如果成功完成所有64位，表示设备存在且处于报警状态
        return SET;
	}
}

/*搜索ROM命令  待完善*/
static ErrorStatus WHT_DS18B20_Driver_Search_ROM(WHT_DS18B20_Config_t* config, unsigned char* output_rom_code)
{
	if (WHT_DS18B20_Driver_Reset(config) == ERROR)
		return ERROR;
	
	WHT_1BUS_Write_1Byte(config, DS18B20_Search_64Bit_ROM_Code);

	for (unsigned char x = 0; x < 8; x++)
	{
		for (unsigned char i = 0x01; i != 0x00; i <<= 1)//LSB
		{
			if (WHT_1BUS_Read_1Bit(config) & WHT_1BUS_Read_1Bit(config))//读取2次
				return ERROR;
			WHT_1BUS_Write_1Bit(config, (WHT_GPIO_State_enum)(output_rom_code[x] & i));
		}
	}
	return SUCCESS;
}

/*获取DS18B20所有数据*/
static void WHT_DS18B20_Driver_Get_RAM_Value(WHT_DS18B20_Config_t* config, WHT_DS18B20_Cache_t* cache, FlagStatus matching_rom)
{
	WHT_DS18B20_Reg_t* DS18B20 = (WHT_DS18B20_Reg_t*)cache;

	if (WHT_DS18B20_Driver_Reset(config) == ERROR)
		return;

	WHT_DS18B20_Driver_Matching_ROM(config, cache, matching_rom);
	WHT_1BUS_Write_1Byte(config, DS18B20_Read_RAM_Value);          //读取暂存寄存器

	for (unsigned char i = 0; i < 9; i++)
	{
		((unsigned char*)cache)[i] = WHT_1BUS_Read_1Byte(config);
	}

	_1BUS_LOGI("DS18B20 Temp_Low      =0x%.2x\r\n", DS18B20->RAM.Temp_Low);
	_1BUS_LOGI("DS18B20 Temp_Hig      =0x%.2x\r\n", DS18B20->RAM.Temp_Hig);
	_1BUS_LOGI("DS18B20 Alert_Temp_Hig=0x%.2x\r\n", DS18B20->RAM.Alert_Temp_Hig);
	_1BUS_LOGI("DS18B20 Alert_Temp_Low=0x%.2x\r\n", DS18B20->RAM.Alert_Temp_Low);
	_1BUS_LOGI("DS18B20 Accuracy      =0x%.2x\r\n", DS18B20->RAM.Accuracy);
	_1BUS_LOGI("DS18B20 Reserve0      =0x%.2x\r\n", DS18B20->RAM.Reserve0);
	_1BUS_LOGI("DS18B20 Reserve1      =0x%.2x\r\n", DS18B20->RAM.Reserve1);
	_1BUS_LOGI("DS18B20 Reserve2      =0x%.2x\r\n", DS18B20->RAM.Reserve2);
	_1BUS_LOGI("DS18B20 CRC8          =0x%.2x\r\n", DS18B20->RAM.CRC8);
}


const WHT_DS18B20_Driver_t WHT_DS18B20_Driver =
{
	.WHT_Config                  = GPIO_Init_Config,
	.WHT_Get_Rom_Code            = WHT_DS18B20_Driver_Get_Rom_Code,
	.WHT_Get_Power_Mode          = WHT_DS18B20_Driver_Get_Power_Mode,
	.WHT_Get_RAM_Value           = WHT_DS18B20_Driver_Get_RAM_Value,

	.WHT_Set_Alarm_Temp_Accuracy = WHT_DS18B20_Driver_Set_Alarm_Temp_Accuracy,
	.WHT_RAM_Value_Copy_EEPROM   = WHT_DS18B20_Driver_RAM_Value_Copy_EEPROM,
	.WHT_EEPROM_Value_Copy_RAM   = WHT_DS18B20_Driver_EEPROM_Value_Copy_RAM,
	//.WHT_Search_All_ROM          = WHT_DS18B20_Driver_Search_ROM,
	.WHT_Convert_Temp            = WHT_DS18B20_Driver_Convert_Temp,
	.WHT_Get_Temp                = WHT_DS18B20_Driver_Get_Temp,
	.WHT_Get_Temp_Alert_Status   = WHT_DS18B20_Driver_Get_Temp_Alert_Status,
};
